package com.itheima.manage.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.commons.pojo.Distribution;

import com.itheima.commons.pojo.User;
import com.itheima.commons.pojo.UserLogin;
import com.itheima.commons.utils.DateTimeUtil;
import com.itheima.commons.vo.DistributionVo;
import com.itheima.commons.vo.LinearVo;
import com.itheima.commons.vo.ProfileInformationVo;
import com.itheima.commons.vo.UserProportionVo;
import com.itheima.interfaces.UserApi;
import com.itheima.interfaces.UserInfoApi;
import com.itheima.interfaces.UserLoginApi;
import com.itheima.interfaces.UserTimeApi;

import com.itheima.manage.exception.MyException;
import com.itheima.manage.exception.ResultError;
import org.springframework.stereotype.Service;

import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.hutool.core.date.DateTime.now;

@Service
public class AppManagePanelInfoService {

    //华北
    private static String L1[] = {"北京", "天津", "河北", "山西", "内蒙"};
    //东北
    private static String L2[] = {"辽宁", "吉林", "黑龙江"};
    //华东
    private static String L3[] = {"上海", "江苏", "浙江", "安徽", "福建", "江西", "山东", "台湾"};
    //华中
    private static String L4[] = {"河南", "湖北", "湖南"};
    //华南
    private static String L5[] = {"广东", "广西", "海南"};
    //西南
    private static String L6[] = {"重庆", "四川", "贵州", "云南", "西藏"};
    //西北
    private static String L7[] = {"陕西", "甘肃", "青海", "宁夏", "新疆"};

    @Reference
    UserApi userService;

    @Reference
    UserInfoApi userInfoService;

    @Reference
    UserLoginApi userLoginService;

    public ProfileInformationVo getSummary() {
        DateTime now = now();
        ProfileInformationVo summaryVo = new ProfileInformationVo();
        //累计用户
        int cumulativeUsers = userService.allCount();
        //过去7天活跃用户
        Integer activePassWeek = userLoginService.findActiveUser(beforeDayOfNow(7L, now), now);
        //过去30天活跃用户
        Integer activePassMonth = userLoginService.findActiveUser(beforeDayOfNow(30L, now), now);
        //今日新增用户
        int usersToday = userService.registerUser(DateUtil.beginOfDay(now).toJdkDate(), now);
        //上月今日新增用户
        int usersLastMonthToday = userService.registerUser(DateUtil.beginOfDay(beforeMonthOfNow(null, now)).toJdkDate(), beforeMonthOfNow(null, now));
        //今日登录次数
        Integer loginUserCount = userLoginService.loginUserCount(DateUtil.beginOfDay(now).toJdkDate(), now);
        //上月今日登录次数
        Integer LastMonthCount = userLoginService.loginUserCount(DateUtil.beginOfDay(beforeMonthOfNow(null, now)).toJdkDate(), beforeMonthOfNow(null, now));
        //今日活跃用户
        Integer activeUsersToday = userLoginService.findActiveUser(DateUtil.beginOfDay(now).toJdkDate(), now);
        //上月今日活跃用户
        Integer activeUsersLastMonthToday = userLoginService.findActiveUser(DateUtil.beginOfDay(beforeMonthOfNow(null, now)).toJdkDate(), beforeMonthOfNow(null, now));
        //昨日活跃用户
        Integer activeUsersYesterday = userLoginService.findActiveUser(beforeDayOfNow(1L, now), now);
        //上月昨日活跃用户
        Integer activeUsersLastMonthYesterday = userLoginService.findActiveUser(DateUtil.beginOfDay(beforeMonthOfNow(1L, now)).toJdkDate(), beforeMonthOfNow(1L, now));
        summaryVo.setCumulativeUsers(cumulativeUsers);
        summaryVo.setActivePassWeek(activePassWeek);
        summaryVo.setActivePassMonth(activePassMonth);
        summaryVo.setUseTimePassWeek(Convert.toInt(betweenUserTime(7L, now) / 7));
        summaryVo.setNewUsersToday(usersToday);
        summaryVo.setNewUsersTodayRate(getRingRatio(usersLastMonthToday, usersToday));
        summaryVo.setLoginTimesToday(loginUserCount);
        summaryVo.setLoginTimesTodayRate(getRingRatio(LastMonthCount, loginUserCount));
        summaryVo.setActiveUsersToday(activeUsersToday);
        summaryVo.setActiveUsersTodayRate(getRingRatio(activeUsersLastMonthToday, activeUsersToday));
        summaryVo.setActiveUsersYesterday(activeUsersYesterday);
        summaryVo.setActiveUsersYesterdayRate(getRingRatio(activeUsersLastMonthYesterday, activeUsersYesterday));
        return summaryVo;
    }

    public Map<String, Object> getUsers(Long sd, Long ed, String type) {
        Map<String, Object> data =  new HashMap<>();
        Date startDate = DateUtil.date(sd).toJdkDate();
        Date endDate = DateUtil.date(ed).toJdkDate();
        List<LinearVo> thisYear = null;
        List<LinearVo> lastYear = null;
        if ("101".equals(type)) {
            List<User> thisYearNewUsers = userService.registerUserList(startDate, endDate);
            List<User> lastYearNewUsers = userService.registerUserList(beforeYearOfDate(1L, startDate), beforeYearOfDate(1L, endDate));
            thisYear = linerValueOfUser(thisYearNewUsers);
            lastYear = linerValueOfUser(lastYearNewUsers);
        }

        if ("102".equals(type)) {
            List<UserLogin> thisYearUser = userLoginService.findUser(startDate, endDate);
            List<UserLogin> lastYearUser = userLoginService.findUser(beforeYearOfDate(1L, startDate), beforeYearOfDate(1L, endDate));
            thisYear = linerValueOfLoginUser(thisYearUser);
            lastYear = linerValueOfLoginUser(lastYearUser);
        }

        if ("103".equals(type)) {
/*            List<User> thisYearNewUsers = userService.registerUserList(startDate, endDate);
            List<User> lastYearNewUsers = userService.registerUserList(beforeYearOfDate(1L, startDate), beforeYearOfDate(1L, endDate));
            List<Long> thisYearNewUsersId = CollUtil.getFieldValues(thisYearNewUsers, "id", Long.class);
            List<Long> lastYearNewUsersId = CollUtil.getFieldValues(lastYearNewUsers, "id", Long.class);
            List<UserLogin> thisYearUser = userLoginService.findLoginCount(startDate, endDate,thisYearNewUsersId);
            List<UserLogin> lastYearUser = userLoginService.findLoginCount(beforeYearOfDate(1L, startDate), beforeYearOfDate(1L, endDate), lastYearNewUsersId);
            thisYear = linerValueOfLoginUser(thisYearUser);
            lastYear = linerValueOfLoginUser(lastYearUser);*/
        }

        data.put("lastYear", lastYear);
        data.put("thisYear", thisYear);
        return data;
    }

    public Map<String, Object> getDistribution(Long sd, Long ed) {
        Map<String, Object> data =  new HashMap<>();
        Date startDate = DateUtil.beginOfDay(DateUtil.date(sd)).toJdkDate();
        Date endDate = DateUtil.date(ed).toJdkDate();
        List<User> userEntities = userService.registerUserList(startDate, endDate);
        List<Long> ids = CollUtil.getFieldValues(userEntities, "id", Long.class);
        if (ObjectUtil.isEmpty(ids)) {
            throw new MyException(ResultError.error());
        }
        List<LinearVo> industryVo = userInfoService.findListGroupByIndustry(ids);
        List<LinearVo> genderVo = userInfoService.findListGroupByGender(ids);
        List<LinearVo> listGroupByAge = userInfoService.findListGroupByAge(ids);
        List<LinearVo> ageVo = parseAge(listGroupByAge);
        List<LinearVo> LocationVo = userInfoService.findListGroupByLocation(ids);
        List<LinearVo> area = parseArea(LocationVo);
        data.put("industryDistribution", industryVo);
        data.put("genderDistribution", genderVo);
        data.put("ageDistribution", ageVo);
        data.put("localDistribution", LocationVo);
        data.put("localTotal", area);
        return data;
    }




    //获取当前时间的前几天时间

    public Date beforeDayOfNow(Long days, Date now) {

        LocalDateTime localDateTime = LocalDateTimeUtil.of(now).plusDays(-days);
        final ZoneId zoneId = ZoneId.systemDefault();
        final ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }


    //获取当前时间的前一月某天时间
    private Date beforeMonthOfNow(Long days, Date now) {
        LocalDateTime time = null;
        LocalDateTime nowTime = LocalDateTimeUtil.of(now);
        if (ObjectUtil.isNotEmpty(days)) {
            time = nowTime.plusDays(-days);
        } else {
            time = nowTime;
        }
        LocalDateTime dateTime = time.plusMonths(-1L);
        final ZoneId zoneId = ZoneId.systemDefault();
        final ZonedDateTime zdt = dateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }
    //获取当前时间的前几年时间

    private Date beforeYearOfDate(Long years, Date now) {
        LocalDateTime nowTime = LocalDateTimeUtil.of(now);
        LocalDateTime dateTime = nowTime.plusYears(-years);
        final ZoneId zoneId = ZoneId.systemDefault();
        final ZonedDateTime zdt = dateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }


    //获取当前时间的前几天秒差值
    private Long betweenUserTime(Long days, Date now) {
        Long betweenTime = 0L;
        List<UserLogin> userLogins = userLoginService.findUser(beforeDayOfNow(days, now), now);
        for (UserLogin userLogin : userLogins) {
            long between = DateUtil.between(userLogin.getOutTime(), userLogin.getLoginTime(), DateUnit.SECOND);
            betweenTime += between;
        }

        return betweenTime;
    }
    //获取环比数值

    private Integer getRingRatio(Integer lastNum, Integer nowNum) {
        NumberFormat numberFormat = NumberFormat.getInstance();
        // 设置精确到小数点后2位
        numberFormat.setMaximumFractionDigits(2);
        String ringRatio = numberFormat.format((float) nowNum / (float) lastNum * 100);
        if (lastNum > nowNum) {
            return -Convert.toInt(ringRatio);
        }
        return Convert.toInt(ringRatio);
    }
    //获得新增用户的线性数据

    private List<LinearVo> linerValueOfUser(List<User> list) {
        Map<String, List<User>> map = new HashMap<>();
        for (User entity : list) {
            if (!map.containsKey(DateUtil.formatDate(entity.getCreated()))) {
                map.put(DateUtil.formatDate(entity.getCreated()), null);
            }
            for (User user : list) {
                List<User> dateList = null;
                if(ObjectUtil.isEmpty(map.get(DateUtil.formatDate(entity.getCreated())))) {
                    dateList = new ArrayList<>();
                } else {
                    dateList = map.get(DateUtil.formatDate(entity.getCreated()));
                }

                if (DateUtil.isSameDay(entity.getCreated(), user.getCreated())) {
                    if (!dateList.contains(user)) {
                        dateList.add(user);
                    }

                }
                map.put(DateUtil.formatDate(entity.getCreated()), dateList);
            }
        }

        List<LinearVo> data = new ArrayList<>();
        Set<String> strings = map.keySet();
        for (String time : strings) {
            LinearVo linearVo = new LinearVo();
            linearVo.setTitle(time);
            linearVo.setAmount(map.get(time).size());
            data.add(linearVo);
        }
        return data.stream().sorted(Comparator.comparing(LinearVo::getTitle)).collect(Collectors.toList());
    }
    //获得活跃用户的线性数据
    private List<LinearVo> linerValueOfLoginUser(List<UserLogin> list) {
        Map<String, List<UserLogin>> map = new HashMap<>();
        for (UserLogin entity : list) {
            if (!map.containsKey(DateUtil.formatDate(entity.getLoginTime()))) {
                map.put(DateUtil.formatDate(entity.getLoginTime()), null);
            }
            for (UserLogin user : list) {
                List<UserLogin> dateList = null;
                if(ObjectUtil.isEmpty(map.get(DateUtil.formatDate(entity.getLoginTime())))) {
                    dateList = new ArrayList<>();
                } else {
                    dateList = map.get(DateUtil.formatDate(entity.getLoginTime()));
                }

                if (DateUtil.isSameDay(entity.getLoginTime(), user.getLoginTime())) {
                    if (!dateList.contains(user)) {
                        dateList.add(user);
                    }

                }
                map.put(DateUtil.formatDate(entity.getLoginTime()), dateList);
            }
        }

        List<LinearVo> data = new ArrayList<>();
        Set<String> strings = map.keySet();
        for (String time : strings) {
            LinearVo linearVo = new LinearVo();
            linearVo.setTitle(time);
            linearVo.setAmount(map.get(time).size());
            data.add(linearVo);
        }
        return data.stream().sorted(Comparator.comparing(LinearVo::getTitle)).collect(Collectors.toList());
    }

    //年龄分布
    private List<LinearVo> parseAge(List<LinearVo> ageList) {
        List<LinearVo> data = new ArrayList<>();
        LinearVo v1 = LinearVo.builder().title("0-17岁").amount(0).build();
        LinearVo v2 = LinearVo.builder().title("18-23岁").amount(0).build();
        LinearVo v3 = LinearVo.builder().title("24-30岁").amount(0).build();
        LinearVo v4 = LinearVo.builder().title("31-40岁").amount(0).build();
        LinearVo v5 = LinearVo.builder().title("41-50岁").amount(0).build();
        LinearVo v6 = LinearVo.builder().title("50+岁").amount(0).build();
        for (LinearVo linearVo : ageList) {
            Integer age = Convert.toInt(linearVo.getTitle());
            if (age > 0 && age <= 17) {
                v1.setAmount(v1.getAmount() + age);
            }

            if (age > 17 && age <= 23) {
                v2.setAmount(v2.getAmount() + age);
            }

            if (age > 23 && age <= 30) {
                v3.setAmount(v3.getAmount() + age);
            }

            if (age > 30 && age <= 40) {
                v4.setAmount(v4.getAmount() + age);
            }

            if (age > 40 && age <= 50) {
                v5.setAmount(v5.getAmount() + age);
            }

            if (age > 50 ) {
                v6.setAmount(v6.getAmount() + age);
            }
        }

        data.add(v1);
        data.add(v2);
        data.add(v3);
        data.add(v4);
        data.add(v5);
        data.add(v6);

        return data;
    }

    //地区分布
    private List<LinearVo> parseArea(List<LinearVo> LocationList) {
        List<LinearVo> data = new ArrayList<>();
        LinearVo v1 = LinearVo.builder().title("华北地区").amount(0).build();
        LinearVo v2 = LinearVo.builder().title("东北地区").amount(0).build();
        LinearVo v3 = LinearVo.builder().title("华东地区").amount(0).build();
        LinearVo v4 = LinearVo.builder().title("华中地区").amount(0).build();
        LinearVo v5 = LinearVo.builder().title("华南地区").amount(0).build();
        LinearVo v6 = LinearVo.builder().title("西南地区").amount(0).build();
        for (LinearVo linearVo : LocationList) {
            String title = linearVo.getTitle();
            if (Arrays.asList(L1).contains(title)) {
                v1.setAmount(v1.getAmount() + linearVo.getAmount());
            }

            if (Arrays.asList(L2).contains(title)) {
                v2.setAmount(v2.getAmount() + linearVo.getAmount());;
            }

            if (Arrays.asList(L3).contains(title)) {
                v3.setAmount(v3.getAmount() + linearVo.getAmount());;
            }

            if (Arrays.asList(L4).contains(title)) {
                v4.setAmount(v4.getAmount() + linearVo.getAmount());;
            }

            if (Arrays.asList(L5).contains(title)) {
                v5.setAmount(v5.getAmount() + linearVo.getAmount());;
            }

            if (Arrays.asList(L6).contains(title)) {
                v6.setAmount(v6.getAmount() + linearVo.getAmount());;
            }
        }

        data.add(v1);
        data.add(v2);
        data.add(v3);
        data.add(v4);
        data.add(v5);
        data.add(v6);

        return data;
    }}
